package com.zfast.yugioh.antlr4.effect.impl;

import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.util.ReflectUtil;
import com.zfast.forge.constant.ExceptionEnum;
import com.zfast.forge.exception.Antlr4Exception;
import com.zfast.yugioh.antlr4.effect.EffectParser;
import com.zfast.yugioh.antlr4.effect.EffectParserBaseListener;
import com.zfast.yugioh.bo.CardBo;
import com.zfast.yugioh.bo.EffectBo;
import com.zfast.yugioh.bo.GameBo;
import com.zfast.yugioh.constant.Define;
import com.zfast.yugioh.constant.VerifyeEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

import static javax.swing.UIManager.get;

public class EffectBaseListenerImpl extends EffectParserBaseListener {
    //region 疑似无效的字段
    @Getter
    @ApiModelProperty("特效参数")
    EffectBo effectBo = new EffectBo();

    @ApiModelProperty("特效语法")
    EffectParser parser;

    public EffectBaseListenerImpl(EffectParser parser) {
        this.parser = parser;
    }
    //endregion
    @Getter
    @Setter
    @ApiModelProperty("游戏参数")
    GameBo gameBo;

    String aimObjectLexerStr,//目标对象_树对象Str
            FromLexerStr,//来源数据组_Str
            TOLexerStr//目的数据组_Str
                    ;
    @Getter
    @ApiModelProperty("特效内部记录参数")
    HashMap expandMap = new HashMap();

    /**
     * 混合语句处理(开始方法)
     * @author  zgn
     * @date    2022/8/16 0016
     * @param	ctx
     * @return	java.lang.Object
     */
    public Object doOrgExpressionParse(ParserRuleContext ctx) {

        List<EffectParser.OrgExpressionContext> SingleContextList = ctx.getRuleContexts(EffectParser.OrgExpressionContext.class);
        List<EffectParser.IfContext> IfContextList = ctx.getRuleContexts(EffectParser.IfContext.class);

        for (int i = 0; i < SingleContextList.size(); i++) {
            EffectParser.OrgExpressionContext orgExpressionContext =  SingleContextList.get(i);
            EffectParser.UpdateContext UpdateContext = orgExpressionContext.getRuleContext(EffectParser.UpdateContext.class, 0);
            this.doUpdateParse(UpdateContext);

        }
        for (int i = 0; i < IfContextList.size(); i++) {
            EffectParser.IfContext ifContext =  IfContextList.get(i);
            if(doWhereParse(ifContext.getRuleContext(EffectParser.ExprContext.class,0),null)){
                System.out.println(ifContext.getRuleContext(EffectParser.ExprContext.class,0).getText());
                this.doUpdateParse(ifContext.getRuleContext(EffectParser.OrgExprContext.class,0)
                        .getRuleContext(EffectParser.OrgExpressionContext.class,0)
                        .getRuleContext(EffectParser.UpdateContext.class,0));
            }
        }

        return null;
    }

    /**
     * 执行单条核心语句
     *
     * @auther zgn
     * @date 2022/6/27
     **/
    //doUpdateParse;enterUpdate
    public void doUpdateParse(EffectParser.UpdateContext ctx) {
        //region 初始值
        ParserRuleContext parent = ctx.getParent();

        EffectParser.FromContext FromContext = parent.getRuleContext(EffectParser.FromContext.class, 0);
        EffectParser.ToContext ToContext = parent.getRuleContext(EffectParser.ToContext.class, 0);
        EffectParser.WhereContext WhereContext = parent.getRuleContext(EffectParser.WhereContext.class, 0);
        EffectParser.LimitContext LimitContext = parent.getRuleContext(EffectParser.LimitContext.class, 0);
        EffectParser.SetObjectContext SetContext = parent.getRuleContext(EffectParser.SetObjectContext.class, 0);
        EffectParser.AimObjectContext ObjectContext = parent.getRuleContext(EffectParser.AimObjectContext.class, 0);

        List<Object> FromDataArrys = new ArrayList<>();//来源数据组_汇总数据
        List<List<Object>> FromArrys = new ArrayList<>();//来源数据组_来源
        List<Object> aimObjects;//目标对象

        boolean IspecialObject=false;
        //endregion

        //region 1.核心动作 coreAct
        effectBo.setCoreAct(Define.UPDATE);
        //endregion

        //region 2.来源数据组:from,where,limit
        //2.1 from
        /*如果存在 From 则获取text
            eg FROMgameDetailBoMe*/
        if (null != FromContext) {
            FromLexerStr = FromContext.getChild(1).getText();

            //zgnHelp {来源数据组}的顺序,影响了筛选的优先顺序
            String[] FromDataArrysStr = FromLexerStr.split(Define.COMMA);
            //2022年8月16日 特定字段ThisCardBo
            if (null != ObjectContext&&ObjectContext.getText().contains(Define.ThisCardBo)) {
                IspecialObject=true;
                FromDataArrys.add(ParserTransformBo(Define.ThisCardBo,CardBo.class,true));
            }

            for (int i = 0; i < FromDataArrysStr.length; i++) {
                //zgnTodo FromContextStr默认了转化出来的都是List trouble_001
                List<Object> objects = (List<Object>) ParserTransformBo(FromDataArrysStr[i], Object.class, false);
                FromArrys.add(objects);
                if(!IspecialObject)
                    try {
                        FromDataArrys.addAll(objects);
                    } catch (NullPointerException e) {
                        throw new Antlr4Exception(ExceptionEnum.field_fail.getDescription()
                                + ":FromContext无法解析或者解析为空"
                        );
                    }
            }
        }

        //2.2 where
        //通过limit,where,梳理{来源数据组}为{目标对象}
        //应该直接解析WhereContext
        //2022年8月5日 where表达式为空
        //zgnTodo trouble_001-->默认aimObject是数组对象
        //2022年8月16日 如果没有筛选条件则为From对象
        if (WhereContext != null) {
            aimObjects = FromDataArrys.stream()
                    .filter(temp ->
                            doWhereParse(WhereContext.where_expr(), temp)
                    )
                    .collect(Collectors.toList());
        }else{
            aimObjects= FromDataArrys;
        }
        //2.3 limit
        effectBo.setIsLimit(false);
        //2.4 limit+where
        if (LimitContext != null) {
            //zgnTodo limit解析方式:字串分割
            List<EffectParser.ExprContext> limitExprsContext = LimitContext.set_expr().getRuleContexts(EffectParser.ExprContext.class);
            //2.3.2 解析LimitContext
            //zgnHelp limit [2值]:start;num;[1值]:num;[0值]:num=卡组数量;
            switch (limitExprsContext.size()) {
                case 1:
                    //默认从零开始
                    effectBo.setLimitStart(BigDecimal.ZERO);
                    effectBo.setLimitNum(doLimitParse(limitExprsContext.get(0)));
                    break;
                case 2:
                    effectBo.setLimitStart(doLimitParse(limitExprsContext.get(0)));
                    effectBo.setLimitNum(doLimitParse(limitExprsContext.get(1)));
                    break;
                /*default:
                    //默认从零开始
                    effectBo.setLimitStart(BigDecimal.ZERO);
                    effectBo.setLimitNum(new BigDecimal(Define.cardNum));
                    break;*/
            }
            effectBo.setIsLimit(true);
            effectBo.setLimitStr(LimitContext.set_expr().getText());

            aimObjects = FromDataArrys.stream()
                    .skip(effectBo.getLimitStart().longValue())
                    .limit(effectBo.getLimitNum().longValue())
                    .collect(Collectors.toList());
        }

        //region 方便测试
        /*System.out.println("--------------------where 判断语句--------------------");
        System.out.println("[来源数据组]数量:"+FromDataArrys.size());
        aimObjects = FromDataArrys.stream()
                .filter(temp -> {
                            boolean b = ExprParse(where_exprContext, temp);
                            CardBo mmm = (CardBo) temp;
                            System.out.println(mmm.getName() + b);
                            return b;
                        }
                )
                .skip(effectBo.getLimitStart().longValue())
                .limit(effectBo.getLimitNum().longValue())
                .collect(Collectors.toList());*/

        /*System.out.println("--------------------简易set动作测试_step1--------------------");
        CardBo testSet = (CardBo) aimObjects.get(0);//handCards3
        testSet.setName("简易set动作测试");//证明了set 可以直接在aimObjects进行反映射*/

        /*System.out.println("--------------------筛选后{目标对象}--------------------");
        for (int i = 0; i < aimObjects.size(); i++) {
            CardBo mmm = (CardBo) aimObjects.get(i);
            System.out.println(mmm.getName());
        }*/
        //endregion
        //endregion

        //region 3.to,set
        //3.1 set
        if (null != SetContext) {
            List<EffectParser.Operator_COLONContext> operator_colonContextList = SetContext.set_expr().getRuleContexts(EffectParser.Operator_COLONContext.class);

            aimObjects.stream()
                    .forEach(temp -> {
                                //反映射
                                doSetParse(operator_colonContextList, temp);
                            }
                    );
        }

        //3.2 to
        if (null != ToContext) {
            //3.2.1从{来源数据组_来源}:FromArrys中剔除
            for (int i = 0; i < FromArrys.size(); i++) {
                FromArrys.get(i).removeAll(aimObjects);
                //System.out.println("断点");
            }
            //3.2.2输送到To{目的数据组}
            TOLexerStr = ToContext.getChild(1).getText();

            //zgnHelp {目的数据组}的顺序,影响了筛选的优先顺序
            String[] ToDataArrysStr = TOLexerStr.split(Define.COMMA);
            for (int i = 0; i < ToDataArrysStr.length; i++) {
                //zgnTodo TOLexerStr默认了转化出来的都是List trouble_002
                List<Object> objects = (List<Object>) ParserTransformBo(ToDataArrysStr[i], Object.class, false);
                objects.addAll(aimObjects);
            }
        }

        //System.out.println("断点");
        //region 方便测试
        /*System.out.println("--------------------set{目标对象}--------------------");
        for (int i = 0; i < aimObjects.size(); i++) {
            CardBo mmm = (CardBo) aimObjects.get(i);
            System.out.println("[名称]:" + mmm.getName() + "\n"
                    + "[特性效果]:" + mmm.getEffectsFeatures() + "\n"
                    + "[登场次数]:" + mmm.getNum() + "\n");
        }*/
        //endregion

        //endregion

        //region 4.aimObject
        if (null != ObjectContext) {
            doObjectParse(ObjectContext);
        }
        //endregion
    }

    /**
     * Object存入expandMap(AS语法解析)
     * @author  zgn
     * @date    2022/8/16 0016
     * @param	ctx
     */
    public void doObjectParse(ParserRuleContext ctx) {

        //System.out.println("--------------------doObjectParse表达式--------------------");
        int childCount = ctx.getChildCount();
        if(childCount==3){//PipeObject: or as:AS
            if(ctx.getChild(1).getText().equals("|")){
                ParserRuleContext exprLeft = (ParserRuleContext)ctx.getChild(0);
                ParserRuleContext exprRight = (ParserRuleContext)ctx.getChild(2);
                doObjectParse(exprLeft);
                doObjectParse(exprRight);
            }
            if(ctx.getChild(1).getText().equals(Define.AS)){
                expandMap.put(ctx.getChild(2).getText(),ParserTransformBo(ctx.getChild(0).getText(), Object.class, false));
                //System.out.println(String.format("表达式3文字 %s|%s|%s ",ctx.getChild(0).getText(),ctx.getChild(1).getText(), ctx.getChild(2).getText()));
                //System.out.println(String.format("表达式3结果 %s|%s|%s ",ParserTransformBo(ctx.getChild(0).getText(), Object.class, false),ctx.getChild(1).getText(), ctx.getChild(2).getText()));
            }
        }
        if(childCount==1){//可直接解析
            //(List<Object>) ParserTransformBo(FromDataArrysStr[i], Object.class, false);
            System.out.print(String.format("表达式1文字 %s ",ctx.getChild(0).getText()));
            System.out.println(String.format("| %s ",ParserTransformBo(ctx.getChild(0).getText(), Object.class, false)));
        }
    }

    /**
     * 递归解析表达式_boolean
     *
     * @param ctx
     * @param temp 目标对象
     * @return boolean
     * @author zgn
     * @date 2022/8/3 0003
     * @date 2022/8/16 核心为判断boolean值,如果temp存在则做expandMap映射;反之,对象隐射
     */
    public boolean doWhereParse(ParserRuleContext ctx, Object temp) {
        //System.out.println("--------------------where 为空的反映射--------------------");
        boolean resullt = true;
        Class<? extends ParserRuleContext> aClass = ctx.getClass();
        List<EffectParser.Where_exprContext> where_exprContextList = ctx.getRuleContexts(EffectParser.Where_exprContext.class);
        List<EffectParser.ExprContext> exprContextList = ctx.getRuleContexts(EffectParser.ExprContext.class);

        List<ParserRuleContext> contextList = new ArrayList<>();
        contextList.addAll(where_exprContextList);
        contextList.addAll(exprContextList);

        //region 递归与或非,括号
        if (aClass.equals(EffectParser.WhereExprOrContext.class)) {//或
            resullt = false;
            for (int i = 0; i < contextList.size(); i++) {
                ParserRuleContext parserRuleContext = contextList.get(i);
                resullt = resullt || doWhereParse(parserRuleContext, temp);
            }
            return resullt;
        }
        if (aClass.equals(EffectParser.WhereExprAndContext.class)) {//与
            for (int i = 0; i < contextList.size(); i++) {
                ParserRuleContext parserRuleContext = contextList.get(i);
                resullt = resullt && doWhereParse(parserRuleContext, temp);
            }
            return resullt;
        }
        if (aClass.equals(EffectParser.WhereExpr_PARENContext.class)//括号
                || aClass.equals(EffectParser.WhereExprObjectContext.class)) {//表达式对象
            return doWhereParse(contextList.get(0), temp);

        }
        //endregion

        String start = ctx.getStart().getText();
        String stop = ctx.getStop().getText().replace("\"", "");

        //region 表达式情况解析
        //System.out.println("--------------------ExprParse_boolean表达式--------------------");
        //System.out.println("ctx.getStart().getText():"+start);
        //System.out.println("ctx.getStop().getText():"+stop.replace("\"",""));

        if(null==temp){
            if (aClass.equals(EffectParser.Operator_EQContext.class)) {//=
                return expandMap.get(start).equals(stop);
            }
            if (aClass.equals(EffectParser.Operator_GTContext.class)) {//>
                return (int)expandMap.get(start)>TransformByClass(stop, Integer.class);
            }
            if (aClass.equals(EffectParser.Operator_LTContext.class)) {//<
                return (int)expandMap.get(start)<TransformByClass(stop, Integer.class);
            }

        }else {
            if (aClass.equals(EffectParser.Operator_EQContext.class)) {//判断表达式
                //去除字串中的双引号
                try {
                    return ReflectUtil.getFieldValue(temp, start).equals(stop);
                } catch (NullPointerException e) {
                    throw new Antlr4Exception(ExceptionEnum.field_fail.getDescription()
                            + String.format(":%n doWhereParse中对象 " +
                            "%n %s " +
                            "%n %s为空 ", temp, start)
                    );
                }
            }


        }
        //endregion

        return resullt;
    }

    /**
     * 递归解析表达式_运算
     *
     * @param ctx //* @param isJudge true:判断;false:赋值仅对EQ有影响,其余表达式无所谓
     * @return java.math.BigDecimal
     * @author zgn
     * @date 2022/7/21 目前只能解析为BigDecimal,来源:{非表达式,嵌套括号,加,减,乘,除}
     */
    public BigDecimal doLimitParse(ParserRuleContext ctx) {
        List<EffectParser.ExprContext> exprs = ctx.getRuleContexts(EffectParser.ExprContext.class);
        BigDecimal exprLeft, exprRight;
        switch (exprs.size()) {
            case 0: //非表达式
                //return ParserTransformBo(ctx.getText(), BigDecimal.class).get(0);
                return ParserTransformBo(ctx.getText(), BigDecimal.class, false);

            case 1: //嵌套括号
                return doLimitParse(exprs.get(0));

            case 2: //双表达式:深入调用{加,减,乘,除}
                exprLeft = doLimitParse(exprs.get(0));
                exprRight = doLimitParse(exprs.get(1));
                if (null == exprLeft || null == exprRight) {
                    throw new Antlr4Exception(ExceptionEnum.func_fail.getDescription()
                            + ":doLimitParse 运算操作符不能为空对象"
                    );
                }
                String operator = ctx.getChild(1).getText();
                switch (operator) {
                    case "+":
                        //System.out.println("ExprParse:+");
                        return exprLeft.add(exprRight).setScale(Define.scale, Define.roundingMode);
                    case "-":
                        //System.out.println("ExprParse:-");
                        return exprLeft.subtract(exprRight).setScale(Define.scale, Define.roundingMode);
                    case "*":
                        //System.out.println("ExprParse:*");
                        return exprLeft.multiply(exprRight).setScale(Define.scale, Define.roundingMode);
                    case "/":
                        //System.out.println("ExprParse:/");
                        return exprLeft.divide(exprRight).setScale(Define.scale, Define.roundingMode);
                    default:
                        throw new Antlr4Exception(ExceptionEnum.func_fail.getDescription()
                                + ":doLimitParse 中暂未能解析'" + operator + "'操作符"
                        );
                }
            default:
                throw new Antlr4Exception(ExceptionEnum.func_fail.getDescription()
                        + ":doLimitParse 3次及以上表达式暂不能解析"
                );
        }
    }

    /**
     * 执行set语句
     *
     * @param operator_colonContextList set:语法内容
     * @param obj                       目标对象
     * @author zgn
     * @date 2022/8/4 0004
     * @date 2022/8/18 如果映射对象为空,且首字母大写则存入expandMap
     */
    public void doSetParse(List<EffectParser.Operator_COLONContext> operator_colonContextList, Object obj) {
        for (int i = 0; i < operator_colonContextList.size(); i++) {
            EffectParser.Operator_COLONContext operator_colonContext = operator_colonContextList.get(i);
            String start = operator_colonContext.getStart().getText();
            String stop = operator_colonContext.getStop().getText();
            try {
                Field field = obj.getClass().getDeclaredField(start);
                field.setAccessible(true);
                //region 方便测试
                System.out.println("--------------------doSetParse的对象反映射参数--------------------");
                System.out.println("[映射参数]:" + stop + "\n"
                        +"[映射对象]:" + field.getType() + "\n");
                //endregion
                field.set(obj, TransformByClass(stop, field.getType()));
            } catch (NoSuchFieldException e) {
                if(start.matches(VerifyeEnum.isFirstCharCase.getRegex())){
                    CardBo obj1 = (CardBo) obj;
                    HashMap expandMap = obj1.getExpandMap();
                    expandMap.put(start,stop);
                }else{
                    e.printStackTrace();
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * 语法转对象,反映射
     *
     * @param parserStr 表达式
     * @param boClass   转化类型(暂时无用)
     * @param isAdd     默认false:未添加隐藏修饰;true:添加了隐藏修饰
     * @return T
     * @author zgn
     * @date 2022-7-20 能检测 数值/树对象/字串;默认gameBo
     * @date 2022-7-22 去掉list包装,设置gameBo优先级
     */
    public <T> T ParserTransformBo(String parserStr, Class<T> boClass, boolean isAdd) {
        //方便测试
        //System.out.println("--------------------ParserTransformBo--------------------");

        //region 特殊字段解析
        if (parserStr.contains(Define.ThisGameDetailBo)) {
            parserStr = parserStr.replace(Define.ThisGameDetailBo, gameBo.getTurn() % 2 == 0 ? Define.gameDetailBoPlayTwo : Define.gameDetailBoPlayOne);
        }
        if (parserStr.contains(Define.RivalGameDetailBo)) {
            parserStr = parserStr.replace(Define.RivalGameDetailBo, gameBo.getTurn() % 2 != 0 ? Define.gameDetailBoPlayTwo : Define.gameDetailBoPlayOne);
        }
        if (parserStr.contains(Define.ThisCardBo)) {
            return (T)effectBo.getCardBo();
        }
        //endregion

        if (parserStr.matches(VerifyeEnum.isNumeric.getRegex())) {
            //3.数值 123
            //list.add((T) Integer.valueOf(parserStr));
            return TransformByClass(parserStr, boClass);
            //list.add(TransformByClass(parserStr, boClass));
        } else {
            //1.树对象 gameDetailBoPlayOne.cards.size 2.字串 "phase"
            //2022年7月21日
            //自定义关键字 能够识别自定义关键字,但是值类型要对应
            String[] split = parserStr.split("\\.");
            Object tempFieldValue = null;
            for (int i = 0; i < split.length; i++) {
                //属于自定义字段
                String tempParserStr = split[i];//叶子对象字串
                //方便测试
                //System.out.println(String.format("是否赋默认前缀:%s %n当下拆解字段:%s %ntemp拆解字段:%s;",isAdd, parserStr, tempParserStr));

                if (tempParserStr.matches(VerifyeEnum.isFirstCharCase.getRegex())) {//自定义对象,未处理null
                    if (i == 0 && !isAdd) {
                        //第一优先级 对象
                        //zgnTodo 默认所有的对象都会先预加载来源数据组,然后再查询gameBo
                        tempFieldValue = ParserTransformBo(FromLexerStr + Define.DOT + parserStr, boClass, true);
                        //第二优先级 gameBo
                        if (null == tempFieldValue)//不能区分
                            tempFieldValue = gameBo.getExpandMap().get(tempParserStr);
                    } else {
                        //zgnHelp ParserTransformBo反映射错误的expandMap会转为null
                        tempFieldValue = ReflectUtil.getFieldValue(tempFieldValue, "expandMap");
                        if (null == tempFieldValue) {
                            return null;
                        }
                        HashMap expandMap = (HashMap) tempFieldValue;
                        tempFieldValue = expandMap.get(tempParserStr);
                    }
                } else {//java反映射
                    if (i == 0) {
                        if (!isAdd) {
                            //第一优先级 对象
                            tempFieldValue = ParserTransformBo(FromLexerStr + Define.DOT + parserStr, boClass, true);
                        }
                        //第二优先级 gameBo
                        if (null == tempFieldValue)
                            tempFieldValue = ReflectUtil.getFieldValue(gameBo, split[i]);
                    } else {
                        tempFieldValue = ReflectUtil.getFieldValue(tempFieldValue, tempParserStr);
                    }
                }

            }
            //list.add((T) tempFieldValue);
            return TransformByClass(tempFieldValue, boClass);
            //list.add(TransformByClass(tempFieldValue, boClass));
        }
        //return tempFieldValue;
    }

    /**
     * 特定对象转换
     *
     * @param obj     对象
     * @param boClass 转换对象的class
     * @return T
     * @author zgn
     * @date 2022/7/21 0021 文字 转 特殊对象
     */
    public <T> T TransformByClass(Object obj, Class<T> boClass) {
        if (null == obj) {
            return null;
        }
        if (boClass.equals(BigDecimal.class)) {//String 转 BigDecimal
            return (T) new BigDecimal(obj.toString());
        }
        if (boClass.equals(Integer.class)) {//String 转 Integer
            return (T) Integer.valueOf(obj.toString());
        }
        return (T) obj;//默认
    }

}
